package com.fw.ui;

import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

import com.fw.ui.bao.MessageBAO;
import com.fw.ui.bao.PropertyBAO;
import com.fw.ui.bean.AuthenticationBean;
import com.fw.ui.core.SpringViewProvider;
import com.fw.ui.core.authentication.AuthenticationUserToken;
import com.fw.ui.util.MyConverterFactory;
import com.fw.ui.util.VaadinApplicationObjectSupport;
import com.fw.ui.view.common.ChangePasswordPanel;
import com.fw.ui.view.common.LoginPanel;
import com.fw.ui.view.event.ApplicationLogoutButtonClickListener;
import com.fw.ui.view.event.ViewChangeEventListener;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.server.Page;
import com.vaadin.server.ThemeResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Image;
import com.vaadin.ui.Label;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
@Theme("mytheme")
@org.springframework.stereotype.Component
@Title("UI Application")
@Scope(SCOPE_PROTOTYPE)
public class ApplicationUI extends UI {

    @Autowired
    protected transient VaadinApplicationObjectSupport app;
    @Autowired
    private ViewChangeEventListener viewChangeEventListener;
    @Autowired
    private ApplicationLogoutButtonClickListener applicationLogoutButtonClickListener;

    @Autowired
    private LoginPanel loginPanel;
    @Autowired
    private ChangePasswordPanel changePasswordPanel;

    @Autowired
    private PropertyBAO propertyBAO;
    @Autowired
    private MessageBAO messageBAO;

    private VerticalLayout root = new VerticalLayout();
    private VerticalLayout headerLayout = new VerticalLayout();
    private VerticalLayout footerLayout = new VerticalLayout();
    private HorizontalLayout menuLayout = new HorizontalLayout();
    private HorizontalLayout subMenuLayout = new HorizontalLayout();
    private VerticalLayout contentLayout = new VerticalLayout();
    private Navigator navigator;

    private Label userDetails = new Label("", ContentMode.HTML);
    private Button btnLogout = new Button("");
    Label label = new Label("", ContentMode.HTML);

    @Override
    protected void init(VaadinRequest request) {
	this.setLocale(Locale.US);
	this.getSession().setConverterFactory(new MyConverterFactory());
	this.setContent(this.root);
	this.root.setId("appLayout");
	this.root.setSizeUndefined();
	this.root.setWidth("100%");

	Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
	// SpringViewProvider securityViewProvider = (SpringViewProvider) SpringViewProvider
	// .createViewProvider((Authentication) authentication);

	boolean isLoginUser = false;
	if (authentication != null && authentication.getAuthorities() != null && authentication.getAuthorities().size() > 1) {
	    isLoginUser = true;
	} else {
	    if (authentication.getAuthorities() != null && authentication.getAuthorities().size() == 1) {
		for (GrantedAuthority authority : authentication.getAuthorities()) {
		    if ("ROLE_ANONYMOUS".equals(authority.getAuthority())) {
			isLoginUser = false;
		    } else if ("ROLE_BASE".equals(authority.getAuthority())) {
			isLoginUser = true;
		    }
		}
	    } else {
		isLoginUser = false;
	    }
	}
	if (!isLoginUser || authentication == null || authentication.getCredentials() == null || authentication.getPrincipal() == null) {
	    // || securityViewProvider.getViews() == null || securityViewProvider.getViews().isEmpty()) {
	    this.buildLoginView(false);
	} else {
	    this.buildMainView(true);
	}

    }

    private void buildNavigator(final boolean forward) {
	this.navigator = new Navigator(this, this.contentLayout);
	this.navigator.addViewChangeListener(this.viewChangeEventListener);

	// SpringViewProvider securityViewProvider = (SpringViewProvider) SpringViewProvider.createViewProvider(false);
	// this.navigator.addProvider(securityViewProvider);

	Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
	final SpringViewProvider securityViewProvider = (SpringViewProvider) SpringViewProvider
		.createViewProvider((Authentication) authentication);
	this.navigator.addProvider(securityViewProvider);

	if (securityViewProvider.getAllViews() != null) {
	    for (Entry<String, Class<? extends View>> entry : securityViewProvider.getAllViews().entrySet()) {
		String navigatePathStr = securityViewProvider.getMapNamePathViews().get(entry.getKey());
		navigator.addView(navigatePathStr, entry.getValue());
	    }
	}
	try {
	    String f = Page.getCurrent().getUriFragment();
	    if (f != null && f.startsWith("!")) {
		f = f.substring(1);
	    }
	    String mainMenuStrAll = propertyBAO.getPropertyValue("common.mainmenu");
	    if (mainMenuStrAll != null) {
		String[] mainMenuArr = mainMenuStrAll.split(",");
		for (String mainMenuStr : mainMenuArr) {
		    String keyPathStr = "view." + mainMenuStr + ".path";
		    String keyTitleStr = "view." + mainMenuStr + ".title";
		    String keyChildStr = "view." + mainMenuStr + ".child";

		    final String pathValue = this.propertyBAO.getPropertyValue(keyPathStr);
		    String titleValue = this.messageBAO.getMessage(keyTitleStr);
		    final String childValue = this.propertyBAO.getPropertyValue(keyChildStr);

		    Button btnMenu = new NativeButton(titleValue);
		    btnMenu.setId("btn" + mainMenuStr + "Menu");
		    btnMenu.addStyleName("menu-item");

		    if (forward) {
			if (f != null && f.startsWith(pathValue)) {
			    btnMenu.addStyleName("selected");
			    if (childValue != null && childValue.trim().length() > 0) {
				this.subMenuLayout.removeAllComponents();
				clearSubMenuSelection();
				String[] subMenuArr = childValue.split(",");
				for (String subMenuStr : subMenuArr) {
				    if (subMenuStr != null && subMenuStr.trim().length() > 0) {
					String keyChildPathStr = "view." + subMenuStr + ".path";
					String keyChildTitleStr = "view." + subMenuStr + ".title";

					final String pathChildValue = propertyBAO.getPropertyValue(keyChildPathStr);
					String titleChildValue = messageBAO.getMessage(keyChildTitleStr);

					Button btnSubMenu = new NativeButton(titleChildValue);
					btnSubMenu.addStyleName("submenu-item");
					if (f != null && f.startsWith(pathChildValue)) {
					    btnSubMenu.addStyleName("selected");
					}
					btnSubMenu.addClickListener(new ClickListener() {
					    @Override
					    public void buttonClick(ClickEvent event) {
						clearSubMenuSelection();
						event.getButton().addStyleName("selected");
						View view = securityViewProvider.getView(pathChildValue);
						if (view != null && !navigator.getState().equals(pathChildValue)) {
						    navigator.navigateTo(pathChildValue);
						}
					    }
					});
					subMenuLayout.addComponent(btnSubMenu);
				    }
				}
				HorizontalLayout horizontalLayout = new HorizontalLayout();
				horizontalLayout.addStyleName("submenu-item-expend");
				subMenuLayout.addComponent(horizontalLayout);
				subMenuLayout.setExpandRatio(horizontalLayout, 1);
			    }
			}
		    }

		    btnMenu.addClickListener(new ClickListener() {
			@Override
			public void buttonClick(ClickEvent event) {
			    try {
				clearMenuSelection();
				event.getButton().addStyleName("selected");
				String f = Page.getCurrent().getUriFragment();
				if (f != null && f.startsWith("!")) {
				    f = f.substring(1);
				}
				if (childValue != null && childValue.trim().length() > 0) {
				    String[] subMenuArr = childValue.split(",");
				    for (String subMenuStr : subMenuArr) {
					if (subMenuStr != null && subMenuStr.trim().length() > 0) {
					    String keyChildPathStr = "view." + subMenuStr + ".path";
					    String keyChildTitleStr = "view." + subMenuStr + ".title";

					    final String pathChildValue = propertyBAO.getPropertyValue(keyChildPathStr);
					    String titleChildValue = messageBAO.getMessage(keyChildTitleStr);

					    Button btnSubMenu = new NativeButton(titleChildValue);
					    btnSubMenu.addStyleName("submenu-item");
					    if (forward) {
						if (f != null && f.startsWith(pathChildValue)) {
						    btnSubMenu.addStyleName("selected");
						}
					    }

					    btnSubMenu.addClickListener(new ClickListener() {
						@Override
						public void buttonClick(ClickEvent event) {
						    clearSubMenuSelection();
						    event.getButton().addStyleName("selected");
						    View view = securityViewProvider.getView(pathChildValue);
						    if (view != null && !navigator.getState().equals(pathChildValue)) {
							navigator.navigateTo(pathChildValue);
						    }
						}
					    });
					    subMenuLayout.addComponent(btnSubMenu);
					}
				    }
				} else {
				    if (!navigator.getState().equals(pathValue))
					navigator.navigateTo(pathValue);
				}
				HorizontalLayout horizontalLayout = new HorizontalLayout();
				horizontalLayout.addStyleName("submenu-item-expend");
				subMenuLayout.addComponent(horizontalLayout);
				subMenuLayout.setExpandRatio(horizontalLayout, 1);

			    } catch (Exception e) {
				e.printStackTrace();
			    }
			}
		    });

		    this.menuLayout.addComponent(btnMenu);
		}
	    }
	} catch (Exception e) {
	    e.printStackTrace();
	}

	if (forward) {
	    if (securityViewProvider.getViews() != null && !securityViewProvider.getViews().isEmpty()) {
		String f = Page.getCurrent().getUriFragment();
		if (f != null && f.startsWith("!")) {
		    f = f.substring(1);
		}
		if (f == null || f.equals("") || f.equals("/")) {
		    String landing = this.propertyBAO.getPropertyValue("common.landing.page");
		    navigator.navigateTo(landing);
		    if (this.menuLayout != null && this.menuLayout.getComponentCount() > 0) {
			this.menuLayout.getComponent(0).addStyleName("selected");
		    }
		} else {
		    if (f.endsWith("/")) {
			f = f.substring(0, f.length() - 1);
		    }
		    View view = securityViewProvider.getView(f);
		    if (view == null) {
			this.contentLayout.removeAllComponents();
		    } else {
			this.navigator.navigateTo(f);
		    }
		}
	    }
	} else {
	    String landing = this.propertyBAO.getPropertyValue("common.landing.page");
	    navigator.navigateTo(landing);
	    if (this.menuLayout != null && this.menuLayout.getComponentCount() > 0) {
		this.menuLayout.getComponent(0).addStyleName("selected");
	    }
	}
    }

    public void buildLoginView(boolean exit) {
	if (exit) {
	    this.root.removeAllComponents();
	}
	this.root.setSizeFull();
	this.loginPanel.initListener();
	this.root.addComponent(this.loginPanel);
	this.root.setExpandRatio(this.loginPanel, 1);
	this.updateStrings();
    }

    public void buildChangePassword() {
	this.root.removeAllComponents();
	this.root.setSizeFull();

	this.changePasswordPanel.setId("changePasswordPanelApp");
	Authentication authentication = (Authentication) SecurityContextHolder.getContext().getAuthentication();
	if (authentication != null && authentication instanceof AuthenticationUserToken) {
	    AuthenticationUserToken userToken = (AuthenticationUserToken) authentication;
	    String oldPassword = userToken.getCredentials().toString();
	    AuthenticationBean authenticationBean = userToken.getAuthenticationBean();
	    this.changePasswordPanel.setUserId(authenticationBean.getUserId());
	    this.changePasswordPanel.setOldPassword(oldPassword);
	}
	String landing = this.propertyBAO.getPropertyValue("common.landing.page");
	this.changePasswordPanel.setNavigatePath(landing);
	this.changePasswordPanel.setRequireNewLogin(true);
	VerticalLayout cLayout = this.changePasswordPanel.getChangePasswordLayout();
	cLayout.setWidth("900px");

	this.root.addComponent(this.changePasswordPanel);
	this.root.setExpandRatio(this.changePasswordPanel, 1);
	this.updateStrings();
    }

    public void buildMainView(boolean forward) {
	this.root.removeAllComponents();
	this.headerLayout.removeAllComponents();
	this.subMenuLayout.removeAllComponents();
	this.contentLayout.removeAllComponents();
	this.footerLayout.removeAllComponents();

	this.root.setSizeUndefined();
	this.root.setWidth("100%");

	// HEADER
	this.headerLayout.setId("headerLayout");
	this.headerLayout.setSizeUndefined();
	this.headerLayout.setWidth("100%");
	this.headerLayout.addStyleName("header-layout");

	// SUBMENU
	this.subMenuLayout.setSizeUndefined();
	this.subMenuLayout.setHeight("30px");
	this.subMenuLayout.setWidth("100%");
	this.subMenuLayout.setId("subMenuLayout");
	this.subMenuLayout.addStyleName("header-submenu-layout");

	HorizontalLayout horizontalLayout = new HorizontalLayout();
	horizontalLayout.addStyleName("submenu-item-expend");
	subMenuLayout.addComponent(horizontalLayout);
	subMenuLayout.setExpandRatio(horizontalLayout, 1);

	// CONTENT
	this.contentLayout.setId("contentLayout");
	this.contentLayout.setSizeUndefined();
	this.contentLayout.setWidth("100%");
	this.contentLayout.addStyleName("content-layout");

	// FOOTER
	this.footerLayout.setId("footerLayout");
	this.footerLayout.setSizeUndefined();
	this.footerLayout.setWidth("100%");
	this.footerLayout.addStyleName("footer-layout");

	this.root.addComponent(this.headerLayout);
	this.root.addComponent(this.subMenuLayout);
	this.root.addComponent(this.contentLayout);
	this.root.addComponent(this.footerLayout);

	this.root.setExpandRatio(this.contentLayout, 1);
	this.root.setComponentAlignment(this.footerLayout, Alignment.MIDDLE_CENTER);

	this.buildHeaderLayout();
	this.buildFooterLayout();
	this.buildNavigator(forward);
	this.updateStrings();
    }

    private void buildHeaderLayout() {
	// MENU
	this.menuLayout.removeAllComponents();
	this.menuLayout.setSizeUndefined();

	this.menuLayout.setId("menuLayout");
	this.menuLayout.setWidth("100%");
	this.menuLayout.addStyleName("header-menu-layout");

	HorizontalLayout mainHeaderlayout = new HorizontalLayout();
	mainHeaderlayout.setSpacing(true);
	mainHeaderlayout.setSizeUndefined();

	ThemeResource iconThemeResource = new ThemeResource("img/AEONLogo.png");
	Image profilePic = new Image(null, iconThemeResource);
	profilePic.addStyleName("header-bandner-icon");

	VerticalLayout vMenulayout = new VerticalLayout();
	vMenulayout.setId("vMenulayout");
	vMenulayout.setSizeFull();
	vMenulayout.setSpacing(true);
	vMenulayout.addStyleName("header-menu-vMenulayout");

	HorizontalLayout hMenulayoutRow = new HorizontalLayout();
	hMenulayoutRow.setId("hMenulayout");
	hMenulayoutRow.setSizeFull();
	hMenulayoutRow.setSpacing(true);
	hMenulayoutRow.addStyleName("header-menu-hMenulayout");

	userDetails.setId("userDetails");
	userDetails.addStyleName("menu-display-user-details");

	btnLogout.addStyleName("button-red");
	btnLogout.addStyleName("margin-spacing-50px");
	btnLogout.setDisableOnClick(true);

	applicationLogoutButtonClickListener.setBasedComponent(this);
	applicationLogoutButtonClickListener.setAutoEnabled(true);
	btnLogout.addClickListener(this.applicationLogoutButtonClickListener);

	hMenulayoutRow.addComponent(this.menuLayout);
	hMenulayoutRow.addComponent(btnLogout);

	vMenulayout.addComponent(userDetails);
	vMenulayout.addComponent(hMenulayoutRow);

	vMenulayout.setComponentAlignment(userDetails, Alignment.BOTTOM_RIGHT);

	mainHeaderlayout.addComponent(profilePic);
	mainHeaderlayout.addComponent(vMenulayout);

	this.headerLayout.addComponent(mainHeaderlayout);
    }

    private void buildFooterLayout() {
	label.setId("lblFooter");
	label.setSizeUndefined();
	label.addStyleName("footer-layout-label");

	this.footerLayout.addComponent(label);
	this.footerLayout.setComponentAlignment(label, Alignment.BOTTOM_CENTER);
    }

    private void clearMenuSelection() {
	for (Iterator<Component> it = this.menuLayout.iterator(); it.hasNext();) {
	    Component next = it.next();
	    if (next instanceof NativeButton) {
		next.removeStyleName("selected");
	    } else if (next instanceof DragAndDropWrapper) {
		((DragAndDropWrapper) next).iterator().next().removeStyleName("selected");
	    }
	}
	this.subMenuLayout.removeAllComponents();
    }

    private void clearSubMenuSelection() {
	for (Iterator<Component> it = this.subMenuLayout.iterator(); it.hasNext();) {
	    Component next = it.next();
	    if (next instanceof NativeButton) {
		next.removeStyleName("selected");
	    } else if (next instanceof DragAndDropWrapper) {
		((DragAndDropWrapper) next).iterator().next().removeStyleName("selected");
	    }
	}
    }

    @Override
    public void attach() {
	super.attach();
    }

    @Override
    public void detach() {
	super.detach();
    }

    private void updateStrings() {
	Page.getCurrent().setTitle(messageBAO.getMessage("application.title"));

	Authentication authentication = (Authentication) SecurityContextHolder.getContext().getAuthentication();
	if (authentication != null && authentication instanceof AuthenticationUserToken) {
	    DateFormat dateFormat = new SimpleDateFormat(this.propertyBAO.getPropertyValue("application.date.format.lastlogin"),
		    this.getLocale());
	    AuthenticationUserToken userToken = (AuthenticationUserToken) authentication;

	    String rolename = "-";
	    String username = "-";
	    String lastLogin = "-";
	    if (userToken != null) {
		AuthenticationBean authenticationBean = userToken.getAuthenticationBean();
		if (authenticationBean != null && authenticationBean.getRoleName() != null
			&& authenticationBean.getRoleName().trim().length() > 0) {
		    rolename = authenticationBean.getRoleName();
		}
		if (authenticationBean != null && authenticationBean.getUsername() != null
			&& authenticationBean.getUsername().trim().length() > 0) {
		    username = authenticationBean.getUsername();
		}
		if (authenticationBean != null && authenticationBean.getLastLoginDate() != null) {
		    lastLogin = dateFormat.format(userToken.getAuthenticationBean().getLastLoginDate());
		}
	    }

	    String[] args = new String[] { rolename, username, lastLogin };
	    String welcomeMsg = this.messageBAO.getMessageWithParams("application.title.header.welcome", args);

	    userDetails.setValue(welcomeMsg);
	}

	label.setValue(this.messageBAO.getMessage("application.title.footer"));
	btnLogout.setCaption(this.messageBAO.getMessage("application.button.logout.caption"));

	this.loginPanel.updateStrings();
    }

    public AuthenticationBean getAuthenticationBean() {
	Authentication authentication = (Authentication) SecurityContextHolder.getContext().getAuthentication();
	if (authentication != null && authentication instanceof AuthenticationUserToken) {
	    AuthenticationUserToken userToken = (AuthenticationUserToken) authentication;
	    if (userToken != null) {
		return userToken.getAuthenticationBean();
	    }
	}
	return null;
    }

}